package lectores;

import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import lectores.parsersXLSX.ProcesadorXLSX;
import lectores.parsersXLSX.XLSXHandler;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.StylesTable;
import org.xml.sax.SAXException;

public class LectorConveniosPrimaPagada extends LectorConvenios {

  private File archivoExcel;
  private Workbook libroConveniosPrimaPagada;
  private int mesSeleccionado;
  private int tipoFiltroPeriodo;
  private final int[] INDICES_DATOS_VALIDOS = {0, 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 22, 36, 37};
  private String queryCampos = "INSERT INTO convenios_pp(PERIODO, ID_AGENTE, SISTEMA_ORIGEN, NOMBRE_AGENTE, ID_RAMO_CONTABLE,"
          + " NOM_RAMO, ID_SUBR_CONTABLE, NOM_SUBRAMO, ID_SUB_RAMO_ORIGEN, ID_PROMOTORIA, NOM_PROMOTORIA, PRIMA_PAGADA,"
          + " MARCA,  SINIES_TOTAL, RAMO, COLUMNA) ";
  private Statement st;
  private boolean metioRegistroMes = false;

  public LectorConveniosPrimaPagada(File archivoExcel, int mesSeleccionado, int tipoFiltroPeriodo, Statement st, HashMap<String, Integer> mesTrim)
          throws InvalidFormatException, FileNotFoundException, IOException, SQLException, SAXException, OpenXML4JException, ParserConfigurationException, ExcelMalFormadoException {
    this.archivoExcel = archivoExcel;
    this.mesSeleccionado = mesSeleccionado;
    this.tipoFiltroPeriodo = tipoFiltroPeriodo;
    this.st = st;
    creaMapeoDañosVida();
    creaMapeoColumnas();
    cargaArchivo(mesTrim);
  }

  void cargaArchivo(HashMap<String, Integer> mesTrim) throws InvalidFormatException, FileNotFoundException, IOException, SQLException, SAXException, OpenXML4JException, ParserConfigurationException, ExcelMalFormadoException {
    creaTablaConvenios();

    if (archivoExcel.getPath().endsWith(".xlsx")) {
      OPCPackage paqueteExcel = OPCPackage.open(archivoExcel.getPath(), PackageAccess.READ);
      ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(paqueteExcel);
      XSSFReader xssfReader = new XSSFReader(paqueteExcel);
      StylesTable styles = xssfReader.getStylesTable();
      XLSXHandler manejadorContenido = new XLSXHandler(styles, strings, this, mesSeleccionado, tipoFiltroPeriodo, mesTrim);
      ProcesadorXLSX procesadorXLSX = new ProcesadorXLSX(manejadorContenido, xssfReader);
      procesadorXLSX.process();
    } else {
      InputStream inp = new FileInputStream(archivoExcel);
      libroConveniosPrimaPagada = WorkbookFactory.create(inp);
      llenaTablaConveniosXLS();
    }

    if (!metioRegistroMes) {
      throw new ExcelMalFormadoException(ExcelMalFormadoException.MES_NO_ENCONTRADO, archivoExcel);
    }
  }

  private void creaTablaConvenios() throws SQLException {
    String sql = null;
    st.executeUpdate("DROP TABLE IF EXISTS convenios_pp");
    sql = "CREATE TABLE convenios_pp (PERIODO INTEGER, ID_AGENTE INTEGER, SISTEMA_ORIGEN VARCHAR(500),"
            + " NOMBRE_AGENTE VARCHAR(500), ID_RAMO_CONTABLE INTEGER, NOM_RAMO VARCHAR(500), ID_SUBR_CONTABLE INTEGER,"
            + " NOM_SUBRAMO VARCHAR(500), ID_SUB_RAMO_ORIGEN INTEGER, ID_PROMOTORIA INTEGER, NOM_PROMOTORIA VARCHAR(500),"
            + " PRIMA_PAGADA DOUBLE, MARCA INTEGER,  SINIES_TOTAL DOUBLE, RAMO INTEGER, COLUMNA INTEGER)";
    st.executeUpdate(sql);
  }

  public void insertaRegistro(String datos, int renglon) throws SQLException, ExcelMalFormadoException {
    datos = datos.replace("'", "&").replace(",", "&").replace("&", "").trim();
    String[] renglonParseado = preparaRenglon(datos);
    if (renglonParseado != null) {
      validaCampos(renglonParseado, renglon);
      String queryValores = construyeSQLValores(renglonParseado, renglon, tipoFiltroPeriodo, mesSeleccionado, archivoExcel);
      if (queryValores != null) {
        st.execute(queryCampos + queryValores);
        metioRegistroMes = true;
      }
    }
  }

  private void llenaTablaConveniosXLS() throws ExcelMalFormadoException, SQLException {
    Sheet hojaConvenios = libroConveniosPrimaPagada.getSheetAt(0);

    Row renglonActual = null;
    for (int j = 1; j < hojaConvenios.getLastRowNum(); j++) {
      renglonActual = hojaConvenios.getRow(j);

      if (renglonActual == null) {
        throw new ExcelMalFormadoException(j, 0, ExcelMalFormadoException.RENGLON_VACIO, archivoExcel);
      }

      String[] valores = preparaRenglon(construyeRenglon(renglonActual));
      if (valores.length != 14) {
        throw new ExcelMalFormadoException(ExcelMalFormadoException.FALTA_COLUMNA, archivoExcel);
      }

      String queryValores = construyeSQLValores(valores, j, tipoFiltroPeriodo, mesSeleccionado, archivoExcel);
      if (queryValores != null) {
        st.executeUpdate(queryCampos + queryValores);
      }
    }
  }

  private String construyeRenglon(Row renglon) {
    String linea = "";
    Cell celdaActual;

    for (int i = 0; i < renglon.getLastCellNum(); i++) {
      celdaActual = renglon.getCell(i);

      String campoActual = "";
      if (celdaActual == null) {
        linea = linea + "|";
        continue;
      }

      boolean eraNumero = true;

      if (celdaActual.getCellType() == Cell.CELL_TYPE_STRING) {
        campoActual = celdaActual.getStringCellValue();
        campoActual = campoActual.replace("'", " ").replace(",", " ").replace(" ", "").trim();
        try {
          Double.parseDouble(campoActual);
        } catch (NumberFormatException nfe) {
          eraNumero = false;
        }

        if (eraNumero) {
          campoActual = "" + Double.parseDouble(campoActual);
        }
      }

      if (celdaActual.getCellType() == Cell.CELL_TYPE_NUMERIC
              && (i == 2 || i == 7 || i == 9 || i == 11)) {
        campoActual = "" + (int) celdaActual.getNumericCellValue();
      } else if (celdaActual.getCellType() == Cell.CELL_TYPE_NUMERIC) {
        campoActual = "" + celdaActual.getNumericCellValue();
      }

      campoActual = campoActual.replace("'", " ").replace(",", " ").replace(" ", "").trim();

      if (i == renglon.getLastCellNum() - 1) {
        linea = linea + campoActual;
      } else {
        linea = linea + campoActual + "|";
      }
    }

    return linea;
  }

  public String[] preparaRenglon(String renglon) {
    String[] datosRenglon = new String[INDICES_DATOS_VALIDOS.length];
    String[] datosParseados = renglon.split("\\|");

    for (int i = 0; i < INDICES_DATOS_VALIDOS.length; i++) {
      String datoActual = datosParseados[INDICES_DATOS_VALIDOS[i]];

      if (INDICES_DATOS_VALIDOS[i] == 36) {
        if (datoActual.equals("")) {
          datoActual = "0";
        } else if (datoActual.trim().equals("X")) {
          datoActual = "1";
        } else if (datoActual.trim().equals("DXP")) {
          return null;
        }
      }

      datosRenglon[i] = datoActual;
    }

    return datosRenglon;
  }

  public void validaCampos(String[] campos, int renglon) throws ExcelMalFormadoException {

    //Valida el periodo
    if (campos[0].equals("P_INV")) {
      if (esFilaVacia(campos)) {
        campos[0] = "0000-00";
        return;
      } else {
        throw new ExcelMalFormadoException(renglon - 1, 0, ExcelMalFormadoException.DATO_INESPERADO, archivoExcel);
      }
    }

    //Valida id_agente
    try {
      Integer.parseInt(campos[1]);
    } catch (Exception ex) {
      throw new ExcelMalFormadoException(renglon - 1, 2, ExcelMalFormadoException.DATO_INESPERADO, archivoExcel);
    }
    if (Integer.parseInt(campos[1]) == -1) {
      throw new ExcelMalFormadoException(renglon - 1, 2, ExcelMalFormadoException.DATO_INESPERADO, archivoExcel);
    }

    //Valida id_ramo_subcontable
    int id_ramo_subc = 0;
    try {
      id_ramo_subc = Integer.parseInt(campos[4]);
    } catch (Exception ex) {
      throw new ExcelMalFormadoException(renglon - 1, 7, ExcelMalFormadoException.DATO_INESPERADO, archivoExcel);
    }
    if (!(id_ramo_subc >= 1 && id_ramo_subc <= 36)) {
      throw new ExcelMalFormadoException(renglon - 1, 7, ExcelMalFormadoException.DATO_INESPERADO, archivoExcel);
    }

    //Valida id_promotoria
    try {
      Integer.parseInt(campos[9]);
    } catch (Exception ex) {
      throw new ExcelMalFormadoException(renglon - 1, 12, ExcelMalFormadoException.DATO_INESPERADO, archivoExcel);
    }
    if (Integer.parseInt(campos[9]) == -1) {
      throw new ExcelMalFormadoException(renglon - 1, 12, ExcelMalFormadoException.DATO_INESPERADO, archivoExcel);
    }

    //Valida primapagada
    try {
      Double.parseDouble(campos[11]);
    } catch (Exception ex) {
      throw new ExcelMalFormadoException(renglon - 1, 22, ExcelMalFormadoException.DATO_INESPERADO, archivoExcel);
    }

    //Valida siniestros
    try {
      Double.parseDouble(campos[13]);
    } catch (Exception ex) {
      throw new ExcelMalFormadoException(renglon - 1, 37, ExcelMalFormadoException.DATO_INESPERADO, archivoExcel);
    }
  }

  private boolean esFilaVacia(String[] campos) {
    boolean filavacia = true;

    for (int i = 1; i < campos.length; i++) {
      if (i == 1 || i == 9) {
        filavacia &= (campos[i].equals("-1") || campos[i].equals("0"));
      } else {
        filavacia &= campos[i].equals("0");
      }
    }

    return filavacia;
  }

  public String construyeSQLValores(String[] valores, int renglon, int tipoFiltroPeriodo, int mesSeleccionado, File archivoExcel) throws ExcelMalFormadoException {
    String queryValores = " VALUES (";
    int mes = -1;
    try {
      mes = Integer.parseInt(valores[0].substring(valores[0].length() - 2));
      valores[0] = "" + mes;
    } catch (NumberFormatException nfe) {
      throw new ExcelMalFormadoException(renglon, 0, ExcelMalFormadoException.TIPO_INESPERADO, archivoExcel);
    }

    switch (tipoFiltroPeriodo) {
      case FILTRO_BONOS_PRODUCCION:
        if (mesSeleccionado % 3 == 0) {
          if (!(mesSeleccionado - 2 <= mes && mes <= mesSeleccionado)) {
            return null;
          }
        }
        break;
      case FILTRO_BONOS_CALIDAD:
        if (mesSeleccionado < mes) {
          return null;
        }
        break;
    }

    for (int k = 0; k < valores.length; k++) {

      boolean esDouble = true;
      if (valores[k].equals("-")) {
        valores[k] = "" + 0.0;
      }

      try {
        Double.parseDouble(valores[k]);
      } catch (NumberFormatException nfe) {
        esDouble = false;
      }

      if (esDouble && (INDICES_DATOS_VALIDOS[k] == 22 || INDICES_DATOS_VALIDOS[k] == 36)) {
        queryValores += valores[k] + ",";
      } else {
        boolean esNumero = true;
        try {
          if (valores[k].length() != 0) {
            Integer.parseInt("" + (valores[k].charAt(0)));
          } else {
            queryValores += "0,";
            continue;
          }
        } catch (NumberFormatException nfe) {
          esNumero = false || (valores[k].charAt(0) == '+' || valores[k].charAt(0) == '-');
        }

        try {
          Integer.parseInt("" + (valores[k].charAt(valores[k].length() - 1)));
        } catch (NumberFormatException nfe) {
          esNumero = false;
        }

        if (esNumero) {
          queryValores += valores[k].replace(" ", "") + ",";
        } else {
          queryValores += "'" + valores[k] + "'" + ",";
        }
      }
    }

    int ramo = clasificaRamo(valores[2], valores[4], archivoExcel);
    int columna = columnaCorresp(valores[2], valores[4]);
    queryValores += ramo + ", " + columna + ")";
    return queryValores;
  }
}
